/**
  ******************************************************************************
  * @file    iic.c
  * @author  ashuai0110
  * @version V1.0
  * @date    2024-01-16
  * @brief   iic驱动,适用于PIC16(L)F1788_9
  *
  ******************************************************************************
  * @attention
  *
  * Change Logs:
  * Date          Author        Notes
  * 2024-01-16    ashuai0110    完成基本内容
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "iic.h"

/* 私有宏定义-----------------------------------------------------------------*/

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
  * @brief  iic初始化(RC3-SCL RC4-SDA)
  * @param  config : 参数结构体
  * @retval None
  */
void iic_init(iic_config_t config)
{
    /* 修改两个引脚为输入 */
    TRISC3 = 1;
    TRISC4 = 1;
    SSP1CON1bits.SSPM = config.mode; /* MSSP的模式选择位 详见手册 */
    SMP = 1; /* 禁用IO速度限制 */
    SSPADD = config.freqDiv - 1; /* MSSP波特率发生寄存器 */
    SSP1IE = 0; /* 关闭中断 */
    SSP1IF = 0;
    SSPEN = 1; /* 使能MSSP */
}

/**
  * @brief  iic取消初始化(恢复缺省)
  * @param  None
  * @retval None
  */
void iic_de_init(void)
{
    SSP1CON1bits.SSPM = 0;
    SMP = 0;
    SSPADD = 0;
    SSPEN = 0;
}

/**
  * @brief  iic启动
  * @param  None
  * @retval None
  */
inline void iic_start(void)
{
    SEN = 1; /* iic启动 */
    while(SEN == 1);
    SSP1IF = 0;
}

/**
  * @brief  iic重新启动
  * @param  None
  * @retval None
  */
inline void iic_restart(void)
{
    RSEN = 1; /* iic重新启动 */
    while(RSEN == 1);
    SSP1IF = 0;
}

/**
  * @brief  iic写一个字节
  * @param  byte : 写入数据
  * @retval None
  */
inline void iic_write(uint8_t byte)
{
    SSP1BUF = byte; /* 写数据 */
    while(ACKSTAT == 1);
    while(SSP1IF == 0);
    SSP1IF = 0;
}

/**
  * @brief  iic读一个字节
  * @param  ack : 0:ACK  1:NAK
  * @retval 读出数据
  */
inline uint8_t iic_read(uint8_t ack)
{
    uint8_t tmp;
    
    RCEN = 1; /* 接收使能 */
    while(SSP1IF == 0);
    SSP1IF = 0;
    tmp = SSP1BUF; /* 数据 */
    ACKDT = ack; /* 0:ACK  1:NAK */
    ACKEN = 1;
    while(SSP1IF == 0);
    SSP1IF = 0;
    
    return tmp;
}

/**
  * @brief  iic停止
  * @param  None
  * @retval None
  */
inline void iic_stop(void)
{
    PEN = 1; /* iic结束 */
}

/**
  * @brief  iic写多个字节
  * @param  addr  : 写地址
  * @param  bytes : 写入数据缓冲区
  * @param  len   : 要写入的数量
  * @retval None
  */
void iic_write_bytes(uint8_t addr, uint8_t *bytes, uint8_t len)
{
    iic_start();
    
    iic_write(addr & 0xFE);
    while(len--)
    {
        iic_write(*bytes++);
    }
    
    iic_stop();
}

/**
  * @brief  iic读多个字节
  * @param  addr  : 读地址
  * @param  bytes : 读出数据存储区
  * @param  len   : 要读出的数量
  * @retval None
  */
void iic_read_bytes(uint8_t addr, uint8_t *bytes, uint8_t len)
{
    iic_start();
    
    iic_write(addr | 0x01);
    while(len--)
    {
        *bytes++ = iic_read(len == 1 ? 1 : 0);
    }
    
    iic_stop();
}
